package com.echovin.esb.gateway.parameter.impl;

import com.echovin.esb.gateway.locator.GatewayParameterValidateResourceLocator;
import com.echovin.esb.gateway.model.TwoTuple;
import com.echovin.esb.gateway.parameter.SchemaValidator;
import lombok.extern.slf4j.Slf4j;
import org.xml.sax.SAXException;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.*;

@Slf4j
public class XMLSchemaValidator implements SchemaValidator {
    private static final String SCHEMALANG = "http://www.w3.org/2001/XMLSchema";
    private GatewayParameterValidateResourceLocator validateResourceLocator;

    public XMLSchemaValidator(GatewayParameterValidateResourceLocator validateResourceLocator) {
        this.validateResourceLocator = validateResourceLocator;
    }

    @Override
    public TwoTuple<Boolean, String> schemaValidator(String requestPath, String bodyStr) {
        Boolean result = false;
        String message = null;
        try {
            // 从数据库查询schema
            String xsdStr = validateResourceLocator.getSchema(requestPath);
            Schema schema = this.schemaFromString(xsdStr);
            //验证器实施/检查此对象表示的约束集。Validator -> 根据 Schema 检查 XML 文档的处理器。
            Validator validator = schema.newValidator();
            //验证指定的输入。 Source -> 实现此接口的对象包含充当源输入（XML 源或转换指令）所需的信息
            InputStream is = new ByteArrayInputStream(bodyStr.getBytes());
            //需要设置编码   否则会出字节解析错误
            InputStreamReader in = new InputStreamReader(is, "UTF-8");
            Source source = new StreamSource(in);
            validator.validate(source);
            result =  true;
        } catch (Exception e) {
            message = e.getMessage();
            log.error("XML文件通过Schema文件校验失败:{}", e.getMessage());
        }
        return new TwoTuple(result, message);

    }

    /**
     * 从字符串中解析Schema，用于校验xml
     *
     * @param xsdStr
     * @return
     */
    private Schema schemaFromString(String xsdStr) {
        try {
            InputStream is = new ByteArrayInputStream(xsdStr.getBytes());
            InputStreamReader in = new InputStreamReader(is, "UTF-8");
            Source xsdsource = new StreamSource(in);
            SchemaFactory factory =
                    SchemaFactory.newInstance(SCHEMALANG);
            Schema schema = factory.newSchema(xsdsource);
            return schema;
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }

    /**
     * 从file中解析Schema，用于校验xml
     *
     * @param fileName
     * @return
     */
    private Schema schemaFromFile(String fileName) {
        try {
            //查找支持指定模式语言的  SchemaFactory 的实现并返回它
            SchemaFactory schemaFactory =
                    SchemaFactory.newInstance(SCHEMALANG);
            // 建立验证文档文件对象，利用此文件对象所封装的文件进行schema验证
            File schemaFile = new File(fileName);
            // 利用schema工厂，接收验证文档文件对象生成Schema对象
            Schema schema = schemaFactory.newSchema(schemaFile);
            return schema;
        } catch (SAXException e) {
            log.error(e.getMessage());
        }
        return null;
    }


}
